package umputun.jutw.utils.logging;

/*
 Copyright 2009 Umputun

 This file is part of JUTW.

 JUTW is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 JUTW is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with JUTW.  If not, see http://www.gnu.org/licenses/.
*/

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.logging.*;


public class ULogger  extends Logger {

	private static volatile ULogger logger = null;


	static public ULogger initLogger(String file, Level level) {
		if (logger == null) {
			synchronized (ULogger.class) {
				logger = new ULogger(file, level);
			}
		}
		return logger;
	}

	static public ULogger initLogger(Level level) {
		String file = getMainClassName();
		if (file == null)
			file = "log";
		file =  "logs/" + file + ".log";
		return initLogger(file, level);
	}

	static public ULogger initLogger(String file) {
		return initLogger(file, null);
	}

	static public ULogger initLogger() {
		Level lv = null;
		return initLogger(lv);
	}

	static public ULogger getLogger() {
		if (logger == null)
			initLogger();
		return logger;
	}


	private ULogger(String file, Level level) {
		super(file, null);
		String dir = new File(file).getParent();
		if (dir != null &&  !(new File(dir).exists()) )
			new File(dir).mkdirs();

		if (level != null)
			setLevel(level);

		this.file = file;

		try {
			setHandler();
		}
		catch (SecurityException e) {
			severe("can't setup exception handler " + e.getMessage());
		}
		catch (IOException e) {
			severe("can't setup exception handler " + e.getMessage());
		}

	}
	private void setHandler() throws SecurityException, IOException {
		Handler handler = new ULoggerHandler(file);
		handler.setFormatter(
			new Formatter() {
				@Override
				public String format(LogRecord rec) {
					GregorianCalendar cal = new GregorianCalendar();
					cal.setTime(new Date());
					StringBuffer buf = new StringBuffer(1000);

					buf.append('[');
					buf.append(rec.getLevel().getName());
					buf.append("] ");

					buf.append(cal.get(Calendar.YEAR)); buf.append('-');
					buf.append(String.format("%02d", cal.get(Calendar.MONTH))); buf.append('-');
					buf.append(String.format("%02d",cal.get(Calendar.DAY_OF_MONTH))); buf.append(' ');
					buf.append(String.format("%02d",cal.get(Calendar.HOUR_OF_DAY))); buf.append(':');
					buf.append(String.format("%02d",cal.get(Calendar.MINUTE))); buf.append(':');
					buf.append(String.format("%02d",cal.get(Calendar.SECOND))); buf.append('.');
					buf.append(String.format("%03d",cal.get(Calendar.MILLISECOND))); buf.append(' ');

					buf.append('{');
					buf.append(rec.getSourceClassName());
					buf.append('.');
					buf.append(rec.getSourceMethodName());
					buf.append("} ");

					buf.append(formatMessage(rec));
					buf.append('\n');
					return buf.toString();
				}
			}
		);
		addHandler(handler);
	}

    public static String getStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }


	public static String getMainClassName() {
		Map<Thread, StackTraceElement[]> s = java.lang.Thread.getAllStackTraces();
		for (Thread t: s.keySet()) {
			StackTraceElement[] st =  s.get(t);
			if (st.length >0) {
				String tmp = st[st.length-1].getClassName();
				if (!tmp.startsWith("java."))
					return tmp;
			}
		}
	    return null;
	}

	public static Level parseLevel(String dbg) {
		Level dbg_level = Level.INFO;
		if (dbg.equals("ALL") || dbg.equals("0")) dbg_level = Level.ALL;
		if (dbg.equals("FINE") || dbg.equals("1")) dbg_level = Level.FINE;
		if (dbg.equals("INFO") || dbg.equals("2")) dbg_level = Level.INFO;
		if (dbg.equals("WARNING") || dbg.equals("WARN") || dbg.equals("3")) dbg_level = Level.WARNING;
		return dbg_level;
	}

	private final String file;

}